//
//  CoordinateQuadTree.m
//  operation4ios
//
//  Created by kjlink on 16/8/29.
//  Copyright © 2016年 阳光电源股份有限公司. All rights reserved.
//

#import "CoordinateQuadTree.h"
#import "ClusterAnnotation.h"
#import "HTMap.h"


//void *debug_Ymalloc(char *fileName, int lineNumber, int size) {
//    void *addr = malloc(size);
//    NSLog(@"%@ %d addr=0x%08X size=%d", [NSString stringWithUTF8String:fileName], lineNumber, (uint32_t)addr, size);
//    return addr;
//}
//
//#define malloc(size) debug_Ymalloc(__FILE__, __LINE__, size)
//
//void debug_Yfree(char *fileName, int lineNumber, void *addr) {
//    
//    NSLog(@"%@ %d addr=0x%08X", [NSString stringWithUTF8String:fileName], lineNumber, (uint32_t)addr);
//    free(addr);
//}
//
//#define free(addr)  do{                                           \
//                        debug_Yfree(__FILE__, __LINE__, addr);    \
//                        addr = NULL;                              \
//                    }while(0)


//此处传入一个字典，里面放的是经纬度
QuadTreeNodeData QuadTreeNodeDataForAMapPOI(MapPS* poi)
{
    return QuadTreeNodeDataMake([poi.latitude doubleValue], [poi.longitude doubleValue], (__bridge_retained void *)(poi));
}

BoundingBox BoundingBoxForMapRect(MAMapRect mapRect)
{
    CLLocationCoordinate2D topLeft = MACoordinateForMapPoint(mapRect.origin);
    CLLocationCoordinate2D botRight = MACoordinateForMapPoint(MAMapPointMake(MAMapRectGetMaxX(mapRect), MAMapRectGetMaxY(mapRect)));
    
    CLLocationDegrees minLat = botRight.latitude;
    CLLocationDegrees maxLat = topLeft.latitude;
    
    CLLocationDegrees minLon = topLeft.longitude;
    CLLocationDegrees maxLon = botRight.longitude;
    
    return BoundingBoxMake(minLat, minLon, maxLat, maxLon);
}

float CellSizeForZoomLevel(double zoomLevel)
{
    /*zoomLevel越大，cellSize越小. */
    if (zoomLevel < 13.0)
    {
        return 64;
    }
    else if (zoomLevel <15.0)
    {
        return 32;
    }
    else if (zoomLevel <18.0)
    {
        return 16;
    }
    else if (zoomLevel < 20.0)
    {
        return 8;
    }
    
    return 64;
}

BoundingBox quadTreeNodeDataArrayForPOIs(QuadTreeNodeData *dataArray, NSMutableArray * pois)
{
    //此处要数组第一个元素的经纬度
        CLLocationDegrees minX = [((MapPS *)[pois firstObject]).latitude doubleValue];
        CLLocationDegrees maxX = [((MapPS *)[pois firstObject]).latitude doubleValue];
//    CLLocationDegrees minX = [[pois[0] objectForKey:@"latitude"] doubleValue];
//    CLLocationDegrees maxX = [[pois[0] objectForKey:@"latitude"] doubleValue];
    
        CLLocationDegrees minY = [((MapPS *)[pois firstObject]).longitude doubleValue];
        CLLocationDegrees maxY = [((MapPS *)[pois firstObject]).longitude doubleValue];
//    CLLocationDegrees minY =[[pois[0] objectForKey:@"longitude"] doubleValue];
//    CLLocationDegrees maxY =[[pois[0] objectForKey:@"longitude"] doubleValue];
    for (NSInteger i = 0; i < [pois count]; i++)
    {
        dataArray[i] = QuadTreeNodeDataForAMapPOI(pois[i]);
        //        NSLog(@"dataArray[i].x:%f",dataArray[i].x);
        //         NSLog(@"dataArray[i].y:%f",dataArray[i].y);
        if (dataArray[i].x < minX)
        {
            minX = dataArray[i].x;
        }
        
        if (dataArray[i].x > maxX)
        {
            maxX = dataArray[i].x;
        }
        
        if (dataArray[i].y < minY)
        {
            minY = dataArray[i].y;
        }
        
        if (dataArray[i].y > maxY)
        {
            maxY = dataArray[i].y;
        }
    }
    
    return BoundingBoxMake(minX, minY, maxX, maxY);
}

#pragma mark -

@implementation CoordinateQuadTree

#pragma mark Utility
/* 查询区域内数据的个数. */


- (NSArray *)clusteredAnnotationsWithinMapRect:(MAMapRect)rect withZoomScale:(double)zoomScale andZoomLevel:(double)zoomLevel
{
    double CellSize = CellSizeForZoomLevel(zoomLevel);
    double scaleFactor = zoomScale / CellSize;
    
    NSInteger minX = floor(MAMapRectGetMinX(rect) * scaleFactor);
    NSInteger maxX = floor(MAMapRectGetMaxX(rect) * scaleFactor);
    NSInteger minY = floor(MAMapRectGetMinY(rect) * scaleFactor);
    NSInteger maxY = floor(MAMapRectGetMaxY(rect) * scaleFactor);
    
    NSMutableArray *clusteredAnnotations = [[NSMutableArray alloc] init];
    for (NSInteger x = minX; x <= maxX; x++)
    {
        for (NSInteger y = minY; y <= maxY; y++)
        {
            MAMapRect mapRect = MAMapRectMake(x / scaleFactor, y / scaleFactor, 1.0 / scaleFactor, 1.0 / scaleFactor);
            
            __block double totalX = 0;
            __block double totalY = 0;
            __block int     count = 0;
            
            NSMutableArray *pois = [[NSMutableArray alloc] init];
            
            /* 查询区域内数据的个数. */
            QuadTreeGatherDataInRange(self.root, BoundingBoxForMapRect(mapRect), ^(QuadTreeNodeData data)
                                      {
                                          totalX += data.x;
                                          totalY += data.y;
                                          count++;
                                          [pois addObject:(__bridge MapPS *)data.data];
                                      });
            
            /* 若区域内仅有一个数据. */
            if (count == 1)
            {
                CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(totalX, totalY);
                ClusterAnnotation *annotation = [[ClusterAnnotation alloc] initWithCoordinate:coordinate count:count];
                annotation.pois = pois;
                
                [clusteredAnnotations addObject:annotation];
            }
            
            /* 若区域内有多个数据 按数据的中心位置画点. */
            if (count > 1)
            {
                CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(totalX / count, totalY / count);
                ClusterAnnotation *annotation = [[ClusterAnnotation alloc] initWithCoordinate:coordinate count:count];
                annotation.pois  = pois;
                
                [clusteredAnnotations addObject:annotation];
            }
        }
    }
    
    return [NSArray arrayWithArray:clusteredAnnotations];
}

#pragma mark Initilization
// 2. 此处接受坐标点
- (void)buildTreeWithPOIs:(NSMutableArray *)pois
{
    //    NSLog(@"----pois.count:%ld",pois.count);
    QuadTreeNodeData *dataArray = malloc(sizeof(QuadTreeNodeData) * [pois count]);
    
    BoundingBox maxBounding = quadTreeNodeDataArrayForPOIs(dataArray, pois);
    
    /*若已有四叉树，清空.*/
    [self clean];
    
    NSLog(@"build tree.");
    /*建立四叉树索引. */ //从此有root
    self.root = QuadTreeBuildWithData(dataArray, [pois count], maxBounding, 4);
    
    free(dataArray);
    dataArray = NULL;
}

#pragma mark Life Cycle

- (void)clean
{
    if (self.root)
    {
        NSLog(@"free tree.");
        FreeQuadTreeNode(self.root);
    }
}

@end
